#include <iostream>
#include <stdexcept>

#include <transport/TSocket.h>
#include <transport/TBufferTransports.h>
#include <protocol/TBinaryProtocol.h>

#include "thrift/CrawlerServer.h"
#include "fetcher.h"

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using boost::shared_ptr;
using namespace crawler::server;
using namespace crawler::client;

static std::string GetHelp() {
  return "Usage: fetcher options\n"
         "  -i     server_ip, default=113.105.248.144\n"
         "  -p     server_port, default=48600\n"
         "  -t     download interval, default=3\n"
         "  -g     get progress\n"
         "  -h     get help";
}
static void ConnectToServer(shared_ptr<CrawlerServerClient> &client,
                     const std::string &ip, int port) {
  boost::shared_ptr<TSocket> socket(new TSocket(ip, port));
  boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
  boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
  client.reset(new CrawlerServerClient(protocol));
  transport->open();
}
static void PrintProgress(shared_ptr<CrawlerServerClient> &client) {
  Progress p;
  client->GetProgress(p);
  std::cout << "total urls :" << p.total_urls << std::endl;
  std::cout << "downloaded urls:" << p.downloaded_urls << std::endl;
  std::cout << ">>>>> url list <<<<<" << std::endl;
  for (std::vector<std::string>::iterator it=p.url_list.begin();
       it!=p.url_list.end(); ++it) {
    std::cout << *it << std::endl;
  }
}
int main(int argc, char **argv)
{
  std::string server_ip("113.105.248.144");
  int server_port = 48600;
  int interval = 3;
  bool print_progress = false;

  // get arguments.
  int opt;
  while ((opt = getopt(argc, argv, "i:p:t:gh")) != -1) {
    switch (opt) {
     case 'i':
      server_ip = optarg;
      break;
     case 'p':
      server_port = atoll(optarg);
      break;
     case 't':
      interval = atoll(optarg);
      break;
     case 'g':
      print_progress = true;
      break;
     case 'h':
      std::cout << GetHelp() << std::endl;
      return EXIT_SUCCESS;
      break;
     case ':':
      std::cerr << "option:" << (char)optopt <<  " needs a value" << std::endl;
      std::cerr << GetHelp() << std::endl;
      return EXIT_FAILURE;
      break;
     case '?':
      std::cerr << "unknow option:" << (char)optopt << std::endl;
      std::cerr << GetHelp() << std::endl;
      return EXIT_FAILURE;
      break;
    }
  }

  shared_ptr<CrawlerServerClient> client;
  bool need_reconnect = true;

  // print the progress if necessary
  if (print_progress) {
    try {
      ConnectToServer(client, server_ip, server_port);
      PrintProgress(client);
    } catch (const ServerError &error) {
      std::cerr << error.why << std::endl;
      return EXIT_FAILURE;
    } catch (const std::exception &ex) {
      std::cerr << ex.what() << std::endl;
      return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
  }

  // enter fetch loop
  while (true) {
    try {
      if (need_reconnect) {
        ConnectToServer(client, server_ip, server_port);
        need_reconnect = false;
      }
      std::string url;
      client->GetDownloadUrl(url);

      std::cout << "downloading url=" << url << std::endl;
      Fetcher fetcher(interval);   
      fetcher.AddUrl(url);
      fetcher.Work();
      std::vector<Page> pages = fetcher.GetFetchedPages();

      for (std::vector<Page>::iterator it=pages.begin(); it!=pages.end(); ++it) {
        std::cout << "sending downloaded page to server, url="
                  << it->url << std::endl;
        client->SendPage(*it);
      }
    } catch (const ServerError &error) {
      std::cerr << error.why << std::endl;
      need_reconnect = true;
      sleep(3);
    } catch (const std::exception &ex) {
      std::cerr << ex.what() << std::endl;
      need_reconnect = true;
      sleep(3);
    }
  }

  return EXIT_SUCCESS;
}

